package com.weiyi.weiman.utils;

import com.github.tobato.fastdfs.domain.fdfs.StorePath;
import com.github.tobato.fastdfs.domain.proto.storage.DownloadFileStream;
import com.github.tobato.fastdfs.service.FastFileStorageClient;
import com.j256.simplemagic.ContentInfo;
import com.j256.simplemagic.ContentInfoUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.csource.fastdfs.ProtoCommon;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.*;

/**
 * @Author zhang
 * @Date 2021/5/1 下午2:21
 * @Description FastDfs工具类，负责上传下载文件
 * @Version 1.0
 **/
@Slf4j
@Component
public class FastDFSUtils {
    @Autowired
    private FastFileStorageClient fastFileStorageClient;

    @Value("${fdfs.web-server-url}")
    private String fastDfsUrl;

    @Value("${fdfs.http.secret_key}")
    private String fastDfsKey;

    @Value("${fdfs.thumb-image.height}")
    private String height;

    @Value("${fdfs.thumb-image.width}")
    private String width;

    //文件上传
    public String uploadFile(MultipartFile file) throws Exception {
        log.info("开始上传文件至FastDFS:{}", file.getName());
        byte[] bytes;
        try {
            bytes = file.getBytes();
        } catch (IOException e) {
            log.error("读取文件错误");
            throw new Exception("读取文件错误");
        }
        //获取源文件名称
        String originalFileName = file.getOriginalFilename();
        //获取文件后缀
        String extension = originalFileName.substring(originalFileName.lastIndexOf(".") + 1);
        //获取文件大小
        long fileSize = file.getSize();
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        StorePath storePath = fastFileStorageClient.uploadFile(byteArrayInputStream, fileSize, extension, null);
        log.info("文件上传至FastDFS成功path:{}", storePath.getFullPath());

        return storePath.getFullPath();
    }

    //文件上传（本地文件）
    public String uploadFile(File file) throws Exception {
        log.info("开始上传文件至FastDFS:{}", file.getName());
        byte[] bytes;
        InputStream inputStream = null;
        try {
            inputStream = openInputStream(file);
            bytes = IOUtils.toByteArray(inputStream, file.length());
        } catch (IOException e) {
            log.error("读取文件错误");
            //关闭输入流
            IOUtils.closeQuietly(inputStream);
            throw new Exception("读取文件错误");
        }
        //获取源文件名称
        String fileName = file.getName();
        //获取文件后缀
        String extension = fileName.substring(fileName.lastIndexOf(".") + 1);
        //获取文件大小
        long fileSize = file.length();
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
        StorePath storePath = fastFileStorageClient.uploadImageAndCrtThumbImage(byteArrayInputStream, fileSize, extension, null);
        log.info("文件上传至FastDFS成功path:{}", storePath.getFullPath());

        //关闭输入流
        IOUtils.closeQuietly(inputStream);
        return storePath.getFullPath();
    }

    //文件转输入流
    public static FileInputStream openInputStream(File file) throws IOException {
        if (file.exists()) {
            if (file.isDirectory()) {
                throw new IOException("文件" + file + "'是一个目录");
            }
            if (!file.canRead()) {
                throw new IOException("文件" + file + "无法读取");
            }
        } else {
            throw new FileNotFoundException("文件" + file + "不存在");
        }
        return new FileInputStream(file);
    }

    /**
     * 文件下载
     *
     * @param fileUrl  示例：group1/M00/00/00/oYYBAF6ZsvCAaQzIAABdreSfEnY579.jpg
     */
    public void downloadFile(String fileUrl, HttpServletResponse response) throws Exception {
        //设置ContentType
        response.setContentType(getContentType(fileUrl));
        //设置keep-alive
        response.setHeader("Connection", "keep-alive");
        ServletOutputStream outputStream;
        try {
            //刷新缓冲
            response.flushBuffer();
            //获取输出流
            outputStream = response.getOutputStream();
        } catch (IOException e) {
            log.error("获取输出流异常", e);
            throw new Exception("获取输出流异常");
        }
        //解析url
        StorePath storePath = StorePath.parseFromUrl(fileUrl);
        //下载文件
        DownloadFileStream downloadFileStream = new DownloadFileStream(outputStream);
        fastFileStorageClient.downloadFile(storePath.getGroup(), storePath.getPath(), downloadFileStream);
        //关闭输出流
        IOUtils.closeQuietly(outputStream);
    }

    /**
     * 文件删除
     *
     * @param fileUrl 示例：group1/M00/00/00/oYYBAF6ZsvCAaQzIAABdreSfEnY579.jpg
     */
    public void deleteFile(String fileUrl) {
        log.info("删除FastFDS文件:{}", fileUrl);
        fastFileStorageClient.deleteFile(fileUrl);
    }

    /**
     * 下载文件时获取ContentType
     *
     * @param fileName 文件名中包含后缀即可
     */
    public String getContentType(String fileName) {
        ContentInfo contentInfo = ContentInfoUtil.findExtensionMatch(fileName);
        if (contentInfo == null) {
            return null;
        }
        return contentInfo.getMimeType();
    }

    /**
     * 获取带有token的访问地址
     *
     * @param fileUrl 示例：group1/M00/00/00/L2ZUml6QisqAUJE3AIOPO1HT6Bo274.mp4
     * @return java.lang.String 示例：http://yourIp:port/files/group1/M00/00/00/L2ZUml6QisqAUJE3AIOPO1HT6Bo274.mp4?token=e9a6ae7f1ecca6fed51e248c6a10d3bc&ts=1589361883
     */
    public String getTokenUrl(String fileUrl) throws Exception {
        String path = StorePath.parseFromUrl(fileUrl).getPath();
        //时间戳 单位为秒
        int ts = (int) (System.currentTimeMillis() / 1000);
        String token;
        try {
            token = ProtoCommon.getToken(path, ts, fastDfsKey);
        } catch (Exception e) {
            log.error("获取token异常", e);
            throw new Exception("FastDFS获取token异常");
        }

        return fastDfsUrl + fileUrl + "?token=" + token + "&ts=" + ts;
    }

    /**
     * 获取缩略图的tokenUrl地址
     * @param fileUrl
     * @return
     * @throws Exception
     */
    public String getThumbImageTokenUrl(String fileUrl) throws Exception {
        String[] data = fileUrl.split("\\.");
        StringBuilder thumbImageUrl = new StringBuilder();
        thumbImageUrl.append(data[0]).append("_").append(height).append("x")
                .append(width).append(".").append(data[1]);
        return getTokenUrl(thumbImageUrl.toString());
    }
}
